<script lang="ts" setup>
import { onMounted, ref, watch, h } from "vue";
import { del, save } from "@/services/doc";
import type { Doc, DocList } from "@/types/doc";
import type { FormInstance, Rule } from "ant-design-vue/es/form";
import { message, type TreeProps } from "ant-design-vue";
import { useGetDocListTree } from "@/composables";
import { useRoute } from "vue-router";
import { getContentById } from "@/services/content";
import { EyeOutlined } from "@ant-design/icons-vue";

const columns = [
  {
    title: "名称",
    dataIndex: "name",
  },
  {
    title: "操作",
    key: "action",
  },
];
const listLoading = ref(false);
const formState = ref<Doc>({});
const formRef = ref<FormInstance | null>(null);
const validateContent = () => {
  // 判断富文本编辑器输入是否为空或回车
  const getText = (str: string) => {
    return str
      .replace(/<[^<p>]+>/g, "") // 将所有<p>标签 replace ''
      .replace(/<[</p>$]+>/g, "") // 将所有</p>标签 replace ''
      .replace(/&nbsp;/gi, "") // 将所有 空格 replace ''
      .replace(/<[^<br/>]+>/g, ""); // 将所有 换行符 replace ''
  };
  const isNull = (str: string) => {
    if (str == "") return true;
    const regu = "^[ ]+$";
    const re = new RegExp(regu);
    return re.test(str);
  };
  if (isNull(getText(valueHtml.value!))) {
    return Promise.reject("内容不允许为空");
  }
  return Promise.resolve();
};
const rules: Record<string, Rule[]> = {
  name: [{ required: true, message: "不允许为空", trigger: "change" }],
  parent: [{ required: true, message: "不允许为空", trigger: "change" }],
  sort: [{ required: true, message: "不允许为空", trigger: "change" }],
  content: [{ required: true, validator: validateContent, trigger: "change" }],
};
const fieldNames: TreeProps["fieldNames"] = {
  children: "children",
  title: "name",
  key: "id",
};
const selectedKeys = ref<number[]>([]);
const treeSelectData = ref<DocList>([]);
const route = useRoute();

// composable
const { docListTree, docListTreeRemoveParent, getDocListTree } = useGetDocListTree(
  Number(route.query.ebookId as string),
);

// 加载列表
const loadList = async () => {
  listLoading.value = true;
  try {
    await getDocListTree();
  } finally {
    listLoading.value = false;
  }
};

// 新增预处理
const prepareAdd = () => {
  // 注意，清空富文本必须用clear，不能直接设置valueHtml为"""
  const editor = editorRef.value;
  if (editor == null) return;
  editor.clear();

  formState.value = { ebookId: Number(route.query.ebookId as string), viewCount: 0, voteCount: 0 };
  treeSelectData.value = JSON.parse(JSON.stringify(docListTreeRemoveParent.value));
  // 问题二：无法设置父节点为顶层节点：
  treeSelectData.value.unshift({ id: 0, name: "无" });
};

// 编辑预处理
const prepareEdit = async (doc: Doc) => {
  // 获取文档内容
  const res = await getContentById(doc.id!);
  valueHtml.value = res.content.content!;

  formState.value = Object.assign({}, doc);

  // 问题一：父节点可选择自己及子节点
  // 将某节点及其子孙节点全部置为disabled
  const setDisable = (treeSelectData: DocList, id: number) => {
    // 遍历数组，即遍历某一层节点
    for (let i = 0; i < treeSelectData.length; i++) {
      const node = treeSelectData[i];
      if (node.id === id) {
        // 如果当前节点就是目标节点
        // 将目标节点设置为disabled
        node.disabled = true;

        // 遍历所有子节点，将所有子节点全部都加上disabled
        if (node.children && node.children.length) {
          for (let j = 0; j < node.children.length; j++) {
            setDisable(node.children, node.children[j].id!);
          }
        }
      } else {
        // 如果当前节点不是目标节点，则到其子节点再找找看。
        if (node.children && node.children.length) {
          setDisable(node.children, id);
        }
      }
    }
  };
  treeSelectData.value = JSON.parse(JSON.stringify(docListTreeRemoveParent.value));
  setDisable(treeSelectData.value, formState.value.id!);
};

// 处理编辑/新增取消
const handleEditOrAddCancel = () => {
  // 对整个表单进行重置，将所有字段值重置为初始值并移除校验结果
  formRef.value?.resetFields();
};

// 处理编辑/新增提交
const handleEditOrAddOk = async () => {
  // 规则校验
  await formRef.value?.validateFields();
  // 发请求
  await save(formState.value, valueHtml.value);
  message.success("success");

  // 请求成功重新加载列表
  await loadList();
  prepareAdd();
};

// 删除
// 删除功能只能删除某个文档，对于无限级的文档树来说，应该将它及它下面的子孙结点全部给删除
const handleDel = async (id: number) => {
  // 在nodes中查找targetId的元素及其所有子元素id
  const findNodeAndCollectIds = (nodes: DocList, targetId: number): number[] => {
    const result: number[] = [];

    // 深度优先遍历函数
    const dfs = (node: Doc): boolean => {
      if (node.id === targetId) {
        collectAllIds(node, result);
        return true;
      }

      if (node.children) {
        for (const child of node.children) {
          if (dfs(child)) return true;
        }
      }
      return false;
    };

    // ID收集函数
    const collectAllIds = (node: Doc, ids: number[]): void => {
      if (node.id !== undefined) {
        ids.push(node.id);
      }
      node.children?.forEach((child) => collectAllIds(child, ids));
    };

    // 遍历所有根节点
    for (const node of nodes) {
      if (dfs(node)) break;
    }

    return result;
  };
  const ids = findNodeAndCollectIds(docListTree.value, id);

  await del(ids.join("."));
  message.success("success");
  // 请求成功重新加载列表
  await loadList();
  prepareAdd();
};

watch(selectedKeys, () => {
  if (selectedKeys.value[0] !== undefined) {
    formState.value.parent = selectedKeys.value[0];
  }
});

onMounted(async () => {
  await loadList();
  // 初始化走新增预处理
  prepareAdd();
});

// ----------------wangeditor----------
import "@wangeditor/editor/dist/css/style.css"; // 引入 css

import { onBeforeUnmount, shallowRef } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef();

const mode = "default";

// 内容 HTML
const valueHtml = ref("");

const toolbarConfig = {};
const editorConfig = { placeholder: "请输入内容..." };

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});

const handleCreated = (editor: unknown) => {
  editorRef.value = editor; // 记录 editor 实例，重要！
};

const open = ref<boolean>(false);
const preview = () => {
  open.value = true;
};
</script>
<template>
  <a-layout>
    <a-layout-content
      :style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
    >
      <a-row :gutter="24">
        <a-col :span="8">
          <a-button @click="prepareAdd" type="primary" style="margin-bottom: 20px">新增</a-button>
          <a-table
            v-if="docListTree.length > 0"
            :columns="columns"
            :data-source="docListTree"
            rowKey="id"
            :loading="listLoading"
            :pagination="false"
            :defaultExpandAllRows="true"
          >
            <template #bodyCell="{ column, record }">
              <template v-if="column.key === 'action'">
                <a-space>
                  <a-button @click="prepareEdit(record)" type="primary" size="small">编辑</a-button>
                  <a-button type="primary" danger size="small">
                    <a-popconfirm
                      title="Are you sure delete this task?"
                      ok-text="Yes"
                      cancel-text="No"
                      @confirm="handleDel(record.id)"
                    >
                      <a href="#">删除</a>
                    </a-popconfirm>
                  </a-button>
                </a-space>
              </template>
            </template>
          </a-table>
        </a-col>
        <a-col :span="16">
          <a-form
            ref="formRef"
            :model="formState"
            :rules="rules"
            :label-col="{ span: 4 }"
            :wrapper-col="{ span: 20 }"
            autocomplete="off"
          >
            <a-form-item label="名称" name="name">
              <a-input v-model:value="formState.name" />
            </a-form-item>
            <a-form-item label="父文档" name="parent">
              <a-tree
                v-model:selectedKeys="selectedKeys"
                :tree-data="treeSelectData"
                :field-names="fieldNames"
              >
              </a-tree>
            </a-form-item>
            <a-form-item label="顺序" name="sort">
              <a-input v-model:value="formState.sort" />
            </a-form-item>
            <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
              <a-button :icon="h(EyeOutlined)" type="primary" @click="preview"> 预览 </a-button>
            </a-form-item>
            <a-form-item label="内容" name="content">
              <div style="border: 1px solid #ccc">
                <Toolbar
                  style="border-bottom: 1px solid #ccc"
                  :editor="editorRef"
                  :defaultConfig="toolbarConfig"
                  :mode="mode"
                />
                <Editor
                  style="height: 500px; overflow-y: hidden"
                  v-model="valueHtml"
                  :defaultConfig="editorConfig"
                  :mode="mode"
                  @onCreated="handleCreated"
                />
              </div>
            </a-form-item>
            <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
              <a-space>
                <a-button @click="handleEditOrAddCancel">重置</a-button>
                <a-button type="primary" @click="handleEditOrAddOk"> 提交 </a-button>
              </a-space>
            </a-form-item>
          </a-form>
        </a-col>
      </a-row>

      <a-drawer v-model:open="open" size="large">
        <div class="editor-content-view" v-html="valueHtml"></div>
      </a-drawer>
    </a-layout-content>
  </a-layout>
</template>
<style></style>
